package org.test4j.integration.junit4.faker;

import org.junit.AfterClass;
import org.junit.Before;

import org.junit.Test;
import org.junit.runners.model.FrameworkMethod;
import org.test4j.integration.ListenerFactory;
import org.test4j.mock.Invocation;
import org.test4j.mock.Mock;
import org.test4j.mock.MockListener;
import org.test4j.mock.MockUp;

import java.lang.reflect.Method;

/**
 * 和 {@link FakeRunNotifier}一起完成完整的{@link MockListener}功能
 *
 * @author darui.wu
 */
public final class FakeFrameworkMethod extends MockUp<FrameworkMethod> {

    @Mock
    public Object invokeExplosively(Invocation inv, Object target, Object... params) throws Throwable {
        FrameworkMethod method = inv.getTarget();
        assert method != null;
        Method testMethod = method.getMethod();
        if (method.getAnnotation(Before.class) != null) {
            ListenerFactory.beforeMethod(target);
            return inv.proceed();
        } else if (method.getAnnotation(AfterClass.class) != null) {
            ListenerFactory.afterMethod();
            return inv.proceed();
        } else if (method.getAnnotation(Test.class) != null) {
            return this.doExecuteTest(inv, target, testMethod);
        } else {
            return inv.proceed();
        }
    }

    private Object doExecuteTest(Invocation inv, Object target, Method testMethod) {
        Throwable e = null;
        try {
            ListenerFactory.beforeExecute(target, testMethod);
            return inv.proceed();
        } catch (Throwable e2) {
            e = e2;
            throw e2;
        } finally {
            ListenerFactory.afterExecute(target, testMethod, e);
        }
    }
}